package 示例代码.sence;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * 该赛马程序主要是通过在控制台不停的打印各赛马的当前轨迹，
 * 以此达到动态显示的效果。
 * 整场比赛有多个轮次，每一轮次各个赛马都会随机走上几步然后调用await方法进行等待，
 * 当所有赛马走完一轮的时候将会执行任务将所有赛马的当前轨迹打印到控制台上。
 * 这样每一轮下来各赛马的轨迹都在不停的增长，
 * 当其中某个赛马的轨迹最先增长到指定的值的时候将会结束整场比赛，该赛马成为整场比赛的胜利者！
 * https://blog.csdn.net/qq_39241239/article/details/87030142
 * @author SunAo
 * @date 2020/8/20 13点09分
 */
public class HourseRace {

    public static class Horse implements Runnable {

        private static int counter = 0;
        private final int id = counter++;
        private int strides = 0;
        private static Random rand = new Random(47);
        private static CyclicBarrier barrier;

        public Horse(CyclicBarrier b) { barrier = b; }

        @Override
        public void run() {
            try {
                while(!Thread.interrupted()) {
                    synchronized(this) {
                        //赛马每次随机跑几步
                        strides += rand.nextInt(3);
                    }
                    barrier.await();
                }
            } catch(Exception e) {
                e.printStackTrace();
            }
        }

        public String tracks() {
            StringBuilder s = new StringBuilder();
            for(int i = 0; i < getStrides(); i++) {
                s.append("*");
            }
            s.append(id);
            return s.toString();
        }

        public synchronized int getStrides() { return strides; }
        public String toString() { return "Horse " + id + " "; }

    }

    private static List<Horse> horses = new ArrayList<Horse>();
    private static ExecutorService exec = Executors.newCachedThreadPool();

    public static class HorseRace implements Runnable {

        private static final int FINISH_LINE = 75;


        @Override
        public void run() {
            StringBuilder s = new StringBuilder();
            //打印赛道边界
            for (int i = 0; i < FINISH_LINE; i++) {
                s.append("=");
            }
            System.out.println(s);
            //打印赛马轨迹
            for (Horse horse : horses) {
                System.out.println(horse.tracks());
            }
            //判断是否结束
            for (Horse horse : horses) {
                if (horse.getStrides() >= FINISH_LINE) {
                    System.out.println(horse + "won!");
                    exec.shutdownNow();
                    return;
                }
            }
            //休息指定时间再到下一轮
            try {
                TimeUnit.MILLISECONDS.sleep(200);
            } catch (InterruptedException e) {
                System.out.println("barrier-action sleep interrupted");
            }
        }

    }

    public static void main(String[] args) {
        CyclicBarrier barrier = new CyclicBarrier(7, new HorseRace());
        for (int i = 0; i < 7; i++) {
            Horse horse = new Horse(barrier);
            horses.add(horse);
            exec.execute(horse);
        }
    }

}
